package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.gwtext.client.core.Function;

import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.SubclassEntityData;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.CancelMergerResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.MergenceResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.actions.MergeEntityResult;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.StkosPanelType;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.interfaces.StkosCallBack;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.accordingdesc.StkosMergerAccordingDescriptionPortlet;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.accordingtree.StkosMergerAccordingTreePortlet;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.currentdesc.StkosMergerCurrentDescriptionPortlet;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.currenttree.StkosMergerCurrentTreePortlet;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.option.StkosMergerOptionPortlet;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.option.StkosMergerOptionView.StkosMergerOptionViewButtonType;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.option.StkosMergerOptionView.StkosMergerOptionViewListBoxType;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.statistical.StkosMergerStatisticalPortlet;
import edu.stanford.bmir.protege.web.client.ui.tab.AbstractTab;
import edu.stanford.bmir.protege.web.shared.DataFactory;
import edu.stanford.bmir.protege.web.shared.PrimitiveType;
import edu.stanford.bmir.protege.web.shared.event.ClassFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.DatatypeFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.EntityFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.EventBusManager;
import edu.stanford.bmir.protege.web.shared.event.NamedIndividualFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.ObjectPropertyFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.hierarchy.ClassHierarchyParentAddedEvent;
import edu.stanford.bmir.protege.web.shared.hierarchy.DataPropertyHierarchyParentAddedEvent;
import edu.stanford.bmir.protege.web.shared.hierarchy.HierarchyId;
import edu.stanford.bmir.protege.web.shared.hierarchy.ObjectPropertyHierarchyParentAddedEvent;
import edu.stanford.bmir.protege.web.shared.project.ProjectDetails;

public class StkosMergerTab extends AbstractTab {

	// column 1

	/** row 1 本体合并选项 */
	private StkosMergerOptionPortlet optionPortlet;

	/** row 2 当前本体树 */
	private StkosMergerCurrentTreePortlet currentTreePortlet;

	/** row 3 当前本体描述 */
	private StkosMergerCurrentDescriptionPortlet currentDescriptionPortlet;

	// column 2
	/** row 1 统计结果 */
	private StkosMergerStatisticalPortlet statisticalPortlet;

	/** row 2 参照本体树 */
	private StkosMergerAccordingTreePortlet accordingTreePortlet;

	/** row 3 参照本体描述 */
	private StkosMergerAccordingDescriptionPortlet accordingDescriptionPortlet;

	public StkosMergerTab(Project project) {
		super(project);
	}

	@Override
	public void setup() {
		super.setup();
		setTitle("合并工具");

		optionPortlet = (StkosMergerOptionPortlet) getPortletByClassName(StkosMergerOptionPortlet.class
				.getName());
		currentTreePortlet = (StkosMergerCurrentTreePortlet) getPortletByClassName(StkosMergerCurrentTreePortlet.class
				.getName());
		currentDescriptionPortlet = (StkosMergerCurrentDescriptionPortlet) getPortletByClassName(StkosMergerCurrentDescriptionPortlet.class
				.getName());

		statisticalPortlet = (StkosMergerStatisticalPortlet) getPortletByClassName(StkosMergerStatisticalPortlet.class
				.getName());
		accordingTreePortlet = (StkosMergerAccordingTreePortlet) getPortletByClassName(StkosMergerAccordingTreePortlet.class
				.getName());
		accordingDescriptionPortlet = (StkosMergerAccordingDescriptionPortlet) getPortletByClassName(StkosMergerAccordingDescriptionPortlet.class
				.getName());

		if (optionPortlet == null || currentTreePortlet == null
				|| currentDescriptionPortlet == null
				|| statisticalPortlet == null || accordingTreePortlet == null
				|| accordingDescriptionPortlet == null) {
			return;
		}

		setControllingPortlet(optionPortlet);

		registerOptionViewEventHandler();
		registerTreeEventHandler();
	}

	protected void registerOptionViewEventHandler() {
		// ListBox accordingProjects change handler
		StkosCallBack accordingProjectsCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				ProjectDetails pd = optionPortlet.getOptionView()
						.getSelectedProjectDetails();
				if (pd == null) {
					updateAccordingProject(null);
				} else {
					AsyncCallback<Project> callback = new AsyncCallback<Project>() {
						@Override
						public void onFailure(Throwable caught) {
							updateAccordingProject(null);
						}

						@Override
						public void onSuccess(Project result) {
							updateAccordingProject(result);
						}
					};
					GWTExtUtil.getProject(pd, callback);
				}
			}
		};
		optionPortlet.getOptionView().setListBoxHandler(
				StkosMergerOptionViewListBoxType.ACCORDINGPROJECT,
				accordingProjectsCB);
		// button autoMerger click handler
		StkosCallBack autoMergerCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				//GWTExtUtil.hideProgressMonitor("自动合并", "自动合并已完成!", 850);
				MergenceResult result = null;
				if (objects == null || objects.length == 0
						|| objects[0] == null) {
				} else {
					currentTreePortlet.onRefresh();
					currentDescriptionPortlet.onRefresh();
					accordingTreePortlet.onRefresh();
					accordingDescriptionPortlet.onRefresh();

					result = (MergenceResult) objects[0];
				}
				statisticalPortlet.getStatisticalView().setMergerResult(result);
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.AUTOMERGER, autoMergerCB);
		// button singleMerger click handler
		StkosCallBack singleMergerCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				//GWTExtUtil.hideProgressMonitor("单条合并", "单条合并已完成!", 850);
				if (objects == null || objects.length == 0
						|| objects[0] == null) {
					return;
				}
				MergeEntityResult result = (MergeEntityResult) objects[0];
				if (currentTreePortlet.getSelectedTreeNode() == null) {
					return;
				}
				EntityData entityData = (EntityData)currentTreePortlet.getSelectedTreeNode()
						.getUserObject();
				if (entityData == null||entityData.getName()==null) {
					return;
				}
				// update subclasses tree
				if(result.getSubClassEntityDataList()!=null&&result.getSubClassEntityDataList().size()!=0){
					PrimitiveType entityType = PrimitiveType.CLASS;
					String parent = entityData.getName(), child = null;
					for(SubclassEntityData sed:result.getSubClassEntityDataList()){
						child = sed.getName();
						if(child!=null){
							break;
						}
					}
					refreshSelectedTreeNode(parent, child, entityType);
				}
				// update individuals tree
				if(result.getNamedIndividualDataList()!=null&&result.getNamedIndividualDataList().size()!=0){
					currentDescriptionPortlet.onRefresh();
				}
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.SINGLEMERGER, singleMergerCB);
		// button showClassDescription click handler
		StkosCallBack showClassDescriptionCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				accordingDescriptionPortlet
						.showPanel(StkosPanelType.CLASS_DESCRIPTION);
				currentDescriptionPortlet
						.showPanel(StkosPanelType.CLASS_DESCRIPTION);
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.SHOWCLASSDESCRIPTION,
				showClassDescriptionCB);
		// button showIndividual click handler
		StkosCallBack showIndividualCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				accordingDescriptionPortlet
						.showPanel(StkosPanelType.INDIVIDUAL_TREE);
				currentDescriptionPortlet
						.showPanel(StkosPanelType.INDIVIDUAL_TREE);
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.SHOWINDIVIDUAL,
				showIndividualCB);
		// button export click handler
		StkosCallBack exportCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				// MessageBox.showAlert("exportResultCB");
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.EXPORT, exportCB);
		// button cancle click handler
		StkosCallBack cancleCB = new StkosCallBack() {
			@Override
			public void onCallBack(Object... objects) {
				// MessageBox.showAlert("cancleCB");
				CancelMergerResult result = null;
				try{
					result = (CancelMergerResult)objects[0];
				} catch(Exception e){
				}
				
				currentTreePortlet.onRefresh();
				currentDescriptionPortlet.onRefresh();
				accordingTreePortlet.onRefresh();
				accordingDescriptionPortlet.onRefresh();
				statisticalPortlet.getStatisticalView().setMergerResult(null);
			}
		};
		optionPortlet.getOptionView().setBtnHandler(
				StkosMergerOptionViewButtonType.CANCEL, cancleCB);
	}

	protected void registerTreeEventHandler() {
		accordingTreePortlet.addListener(GWTExtUtil.EVENT_ONSELECTIONCHANGE,
				new Function() {
					@Override
					public void execute() {
						updateAccordingProjectDescriptionPortletTreeNode();
					}
				});

		currentTreePortlet.addListener(GWTExtUtil.EVENT_ONSELECTIONCHANGE,
				new Function() {
					@Override
					public void execute() {
						updateCurrentProjectDescriptionPortletTreeNode();
						updateOptionViewSelectedTreeNode();
					}
				});
	}

	protected void updateAccordingProjectDescriptionPortletTreeNode() {
		accordingDescriptionPortlet.setSelectedTreeNode(accordingTreePortlet
				.getSelectedTreeNode());
	}

	protected void updateCurrentProjectDescriptionPortletTreeNode() {
		currentDescriptionPortlet.setSelectedTreeNode(currentTreePortlet
				.getSelectedTreeNode());
	}
	
	protected void updateOptionViewSelectedTreeNode(){
		String entityName = null;
		if(currentTreePortlet.getSelectedTreeNode()!=null&&currentTreePortlet.getSelectedTreeNode().getUserObject()!=null){
			entityName = ((EntityData)currentTreePortlet.getSelectedTreeNode().getUserObject()).getName();
		}
		optionPortlet.getOptionView().setEntityName(entityName);
	}

	protected void updateAccordingProject(Project accordingProject) {
		accordingTreePortlet.setAccordingProject(accordingProject);
		accordingDescriptionPortlet.setAccordingProject(accordingProject);
		
		currentTreePortlet.setAccordingProject(accordingProject);
		currentDescriptionPortlet.setAccordingProject(accordingProject);
	}

	protected void refreshSelectedTreeNode(String parent, String child,
			PrimitiveType entityType) {
		if (project == null || project.getProjectId() == null || parent == null) {
			return;
		}
		EventBusManager manager = EventBusManager.getManager();
		List<EntityFrameChangedEvent> events = new ArrayList<EntityFrameChangedEvent>();
		if (PrimitiveType.CLASS.equals(entityType)) {
			ClassFrameChangedEvent event = new ClassFrameChangedEvent(
					DataFactory.getOWLClass(parent), project.getProjectId());
			events.add(event);

			if (child != null) {
				ClassHierarchyParentAddedEvent chpae = new ClassHierarchyParentAddedEvent(
						project.getProjectId(), DataFactory.getOWLClass(child),
						DataFactory.getOWLClass(parent),
						HierarchyId.CLASS_HIERARCHY);
				manager.postEvent(chpae);
			}
		}
		if (PrimitiveType.DATA_PROPERTY.equals(entityType)) {
			DatatypeFrameChangedEvent event2 = new DatatypeFrameChangedEvent(
					DataFactory.getOWLDatatype(parent), project.getProjectId());
			events.add(event2);

			if (child != null) {
				DataPropertyHierarchyParentAddedEvent dhpae = new DataPropertyHierarchyParentAddedEvent(
						project.getProjectId(),
						DataFactory.getOWLDataProperty(child),
						DataFactory.getOWLDataProperty(parent),
						HierarchyId.DATA_PROPERTY_HIERARCHY);
				manager.postEvent(dhpae);
			}
		}
		if (PrimitiveType.OBJECT_PROPERTY.equals(entityType)) {
			ObjectPropertyFrameChangedEvent event3 = new ObjectPropertyFrameChangedEvent(
					DataFactory.getOWLObjectProperty(parent),
					project.getProjectId());
			events.add(event3);

			if (child != null) {
				ObjectPropertyHierarchyParentAddedEvent ohpae = new ObjectPropertyHierarchyParentAddedEvent(
						project.getProjectId(),
						DataFactory.getOWLObjectProperty(child),
						DataFactory.getOWLObjectProperty(parent),
						HierarchyId.OBJECT_PROPERTY_HIERARCHY);
				manager.postEvent(ohpae);
			}
		}

		if (PrimitiveType.NAMED_INDIVIDUAL.equals(entityType)) {
			NamedIndividualFrameChangedEvent event4 = new NamedIndividualFrameChangedEvent(
					DataFactory.getOWLNamedIndividual(parent),
					project.getProjectId());
			events.add(event4);
		}

		if (events != null && events.size() > 0) {
			for (EntityFrameChangedEvent event : events) {
				if (event != null) {
					manager.postEvent(event);
				}
			}
		}
	}
}
